<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="text/css" http-equiv="Content-Style-Type">
<title>SpringBoot</title>
</head>
<body>
<h1 align="center" class="root">
<a name="302vn31p6vj2t0tmuubnb9hct4">SpringBoot</a>
</h1>
<div align="center" class="globalOverview">
<img src="SpringBoot_files/images/SpringBoot 2.jpg"></div>
<h2 class="topic">
<a name="40j1phngub62a2br9tsj5o729s">SpringBoot应用回顾</a>
</h2>
<h3 class="topic">
<a name="6hue67nkfc969dr72plorui0st">&nbsp;约定优于配置</a>
</h3>
<h3 class="topic">
<a name="6j6da6ubc7scoq3ghk6kb7jh3r">&nbsp;&nbsp;按约定编程，是一种软件设计规范。&#13;
本质上是对系统、类库或者框架中一些东西假定一个大众化合理的默认值&#13;
优点：减少配置项，节省配置时间</a>
</h3>
<h3 class="topic">
<a name="54qnvln4h6m170oi9fbgl4h6dl">&nbsp;SpringBoot概念</a>
</h3>
<h3 class="topic">
<a name="3ehug8ne2l3tc7e6gth7tuu8k6">&nbsp;&nbsp;什么是SpringBoot</a>
</h3>
<h3 class="topic">
<a name="0vh981nun781pt5kr5c4fimrhs">&nbsp;&nbsp;&nbsp;Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". </a>
</h3>
<h3 class="topic">
<a name="2v0aoeie5pc3rrek7ccitn3l5h">&nbsp;&nbsp;&nbsp;1. 基于 Spring 的独立的生产级别的应用&#13;
2. 只需要 run</a>
</h3>
<h3 class="topic">
<a name="5ugjbc5vg7ohrrop6qgd4llaub">&nbsp;&nbsp;SpringBoot主要特性</a>
</h3>
<h3 class="topic">
<a name="1d76flbpedrvjggliui6ds50na">&nbsp;&nbsp;&nbsp;SpringBoot Starter (起步依赖) ：对常用的依赖分组进行了整合</a>
</h3>
<h3 class="topic">
<a name="5gu6kr2edqu7d2hr9c20f0abi7">&nbsp;&nbsp;&nbsp;自动配置：合理地推测应用所需的bean并对其自动化配置</a>
</h3>
<h3 class="topic">
<a name="2gu38jpn5ibf926bjk9thrtl2e">&nbsp;&nbsp;&nbsp;使编码变得简单：采用JavaConfig的方式对Spring进行配置</a>
</h3>
<h3 class="topic">
<a name="2lj1r8aqfvne4sm3gognduc2q8">&nbsp;&nbsp;&nbsp;使部署变得简单：内置三种Servlet容器：Tomcat、Jetty、undertow。&#13;
SpringBoot项目可以打成一个jar包</a>
</h3>
<h3 class="topic">
<a name="1ne2kpgr7obcjho2to714o0ape">&nbsp;SpringBoot案例实现</a>
</h3>
<h3 class="topic">
<a name="783jvg9fq7dv76kmduov319mpg">&nbsp;&nbsp;1. 使用Spring Initializr方式构建Spring Boot项目</a>
</h3>
<h3 class="topic">
<a name="7kofv4ts2oak8b171pclgjivme">&nbsp;&nbsp;2. 创建controller</a>
</h3>
<h3 class="topic">
<a name="6a1e0iqvu8bkmvnuh9akv8mtj4">&nbsp;&nbsp;3. 启动项目</a>
</h3>
<h3 class="topic">
<a name="1cikgqk9vq9q55in870a5stvb4">&nbsp;&nbsp;4. 疑问</a>
</h3>
<h3 class="topic">
<a name="1jicfdhrbbhn5bbm24s6gjul89">&nbsp;热部署</a>
</h3>
<h3 class="topic">
<a name="267ikgfnt839fkk3tcoefmijjc">&nbsp;&nbsp;依赖spring-boot-devtools</a>
</h3>
<h3 class="topic">
<a name="53mppiuqi3kccgkarjlhrcjvnb">&nbsp;&nbsp;原理： As DevTools monitors classpath resources, the only way to trigger a restart is to update the classpath. （监控classpath资源变化）&#13;
&#13;
Restart and Reload：采用了base-classloader (加载第三方jar包之类的静态资源) 和restartClassLoader (加载自己编写的类) 两种类加载器</a>
</h3>
<h3 class="topic">
<a name="36r91plt7vm1k311isa3c6e68b">&nbsp;&nbsp;排除资源：某些资源在修改之后不需要热部署重启&#13;
spring.devtools.restart.exclude=static/**,public/**</a>
</h3>
<h3 class="topic">
<a name="1cdon2vnf8p8mg470jlmdsfhkd">&nbsp;全局配置文件</a>
</h3>
<h3 class="topic">
<a name="2qa75lg3a5ep8uid61u8rt350t">&nbsp;&nbsp;优先级：&#13;
1. -file/config/ &gt; -file ./ &gt; -classpath:/config/ &gt; -classpath:/&#13;
2. application.properties &gt; application.yaml （2.4.0版本后相反）&#13;
3. 多个配置文件 互补</a>
</h3>
<h3 class="topic">
<a name="5psi05h5odt2dak9jsr2dhsl6c">&nbsp;&nbsp;application.properties&#13;
自定义对象属性：&gt;spring-boot-configuration-processor</a>
</h3>
<h3 class="topic">
<a name="2q27uiruslhl0gtih9rnm78860">&nbsp;&nbsp;application.yml : YAML文件格式是SpringBoot支持的一种JSON超集文件格式&#13;
使用 &ldquo;key:（空格）value&rdquo;格式配置属性，使用缩进控制层级关系</a>
</h3>
<h3 class="topic">
<a name="3spfq8hosb0g2ml13vgb0fmim1">&nbsp;属性注入</a>
</h3>
<h3 class="topic">
<a name="5rdsicu0d544uk1v2s8l2b1jmh">&nbsp;&nbsp;@Value：&#13;
1. 无须写get/set方法&#13;
2. 单个注入&#13;
3. 支持SpEL表达式 #{}</a>
</h3>
<h3 class="topic">
<a name="0os3f7g57rnhmvva86p73mcls6">&nbsp;&nbsp;@ConfigurationPorperties&#13;
1. 批量注入&#13;
2. 第三方（jar包）配置注入&#13;
3. 支持松散绑定&#13;
4. 元数据支持</a>
</h3>
<h3 class="topic">
<a name="38fcu2u912vgabaas6fsm1bu3u">&nbsp;&nbsp;松散绑定：环境属性名和bean属性名不需要完全匹配</a>
</h3>
<h3 class="topic">
<a name="45qopn7i19f4rcd51ouio9jq44">&nbsp;SpringBoot日志框架</a>
</h3>
<h3 class="topic">
<a name="4c3t2cnjenqugcfjiqnptgv71t">&nbsp;&nbsp;构建设计思想： 日志抽象层 + 具体实现层&#13;
抽象层：JCL(Jakarta Commons Logging) 、SLF4J(Simple Logging Facade for Java) 、jboss-logging&#13;
实现层：jul(java.util.logging)、log4j、logback、log4j2&#13;
&#13;
Spring 框架选择使用了JCL作为默认日志输出&#13;
SpringBoot默认选择了SLF4J结合logback</a>
</h3>
<h3 class="topic">
<a name="661ahd1eblitmis82kdcbjlncu">&nbsp;&nbsp;SLF4J的使用</a>
</h3>
<h3 class="topic">
<a name="377bg0qgnsqo44dj73vbvssq71">&nbsp;&nbsp;统一日志框架的使用&#13;
1. 排除系统中的其他日志框架。&#13;
2. 使用中间包替换要替换的日志框架。&#13;
3. 导入我们选择的 SLF4J 实现。</a>
</h3>
<h3 class="topic">
<a name="4agqpovbglmhkr1dkreo723dhp">&nbsp;&nbsp;SpringBoot日志关系&#13;
1. 自动适配原有框架的日志框架&#13;
2. 如需引入其它框架，则需手动排除其日志框架</a>
</h3>
<h3 class="topic">
<a name="7858tn42dqqdbqiggb14hqj4n5">&nbsp;&nbsp;SpringBoot日志使用&#13;
1. 默认日志级别为 INFO&#13;
2. 默认日志格式是 ：&#13;
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</a>
</h3>
<h3 class="topic">
<a name="1pk7uja7u1r2sb9es0la6k24n0">&nbsp;&nbsp;SpringBoot自定义日志输出</a>
</h3>
<h3 class="topic">
<a name="2mqjf5n16q7o8mqbsl5nfokdtc">&nbsp;&nbsp;SpringBoot日志替换框架</a>
</h3>
<h2 class="topic">
<a name="097lfeeclsavhfpe8s7r3gn2io">SpringBoot源码分析</a>
</h2>
<h3 class="topic">
<a name="4p62jv9kfl1pht0nquc8b0gjtm">&nbsp;源码环境搭建</a>
</h3>
<h3 class="topic">
<a name="2687eptgun6flmq6qacrrdn22g">&nbsp;&nbsp;1. 下载源码：&#13;
使用spring-boot-2.2.9.RELEASE版本，用maven构建（2.3.0之后使用gradle构建）</a>
</h3>
<h3 class="topic">
<a name="5u9nipjoddts9g4rc4dcgtbve1">&nbsp;&nbsp;2. 环境准备：&#13;
jdk1.8 + maven3.5.x</a>
</h3>
<h3 class="topic">
<a name="46g94tfuc5s2dne6vj0c2rq9kn">&nbsp;&nbsp;3. 导入IDEA &#13;
关闭maven代码检查：&lt;disable.checks&gt;true&lt;/disable.checks&gt;</a>
</h3>
<h3 class="topic">
<a name="5g1ss51ekl6sk846fsrqlek67a">&nbsp;&nbsp;4. 新建一个module + 一个controller</a>
</h3>
<h3 class="topic">
<a name="0222h6thl0erk7ju8u45i2vd09">&nbsp;依赖管理</a>
</h3>
<h3 class="topic">
<a name="3nk5aarispi61grair7vc6a7lm">&nbsp;&nbsp;为什么导入dependency时有部分不需要指定版本？&#13;
因为在spring-boot-dependencies中作了许多版本声明。</a>
</h3>
<h3 class="topic">
<a name="0u8l5vp775dqj6p6r4epnk6kqm">&nbsp;&nbsp;项目运行依赖的JAR包是从何而来的？&#13;
例：spring-boot-starter-web依赖启动器的主要作用是打包了Web开发场景所需的底&#13;
层所有依赖</a>
</h3>
<h3 class="topic">
<a name="07mind2gvvona70vqp6tr1hpvt">&nbsp;自动配置</a>
</h3>
<h3 class="topic">
<a name="6aimuj8c60voakd5phs5seapds">&nbsp;&nbsp;@SpringBootApplication&#13;
&#13;
1. @SpringBootConfiguration  // 标记该类为配置类&#13;
2. @EnableAutoConfiguration // 启动自动配置功能&#13;
【自动配置：根据jar包依赖，自动将配置类的bean注册到IOC容器中】&#13;
3. @ComponentScan() // 注解扫描</a>
</h3>
<h3 class="topic">
<a name="0faag5dakq8q9fsj3qn4re9q3c">&nbsp;&nbsp;@EnableAutoConfigurtion&#13;
&#13;
1. @AutoConfigurationPackage注册一个Bean：BasePackages&#13;
参数result是使用了 @AutoConfigurationPackage 所在的包路径,保存自动配置&#13;
类以供之后的使用&#13;
AutoConfigurationPackages.Registrar&#13;
2. @Import&#13;
以 Enable 开头的注解，其作用就是借助 @Import 来收集并注册特定场景相关的&#13;
Bean ，并加载到 IOC 容器</a>
</h3>
<h3 class="topic">
<a name="4vsafr21p0jl7krs0bo4ujhqva">&nbsp;&nbsp;&nbsp;@Import(AutoConfigurationImportSelector.class))&#13;
Spring的底层注解，给容器中导入一个组件</a>
</h3>
<h3 class="topic">
<a name="251mdi0400u5du24lee2vovikv">&nbsp;&nbsp;&nbsp;SpringBoot自动配置过程剖析</a>
</h3>
<h3 class="topic">
<a name="6k0kucki5ct674rcvafm25tp04">&nbsp;&nbsp;&nbsp;&nbsp;@Conditional 条件注解</a>
</h3>
<h3 class="topic">
<a name="5d2l0eodp2869tftktklg8n3vv">&nbsp;&nbsp;&nbsp;1. AutoConfigurationImportSelector.class 继承 DeferredImportSelector 自动装配入口 getImports() 方法；&#13;
2. 调用AutoConfigurationImportSelector中的process()过程；&#13;
3. 在这过程中 从spring.factories配置文件中加载自动配置类；&#13;
4. 加载的自动配置类中排除掉 @EnableAutoConfiguration 注解的 exclude 属性指定的自动配置类；&#13;
5. 然后再用 AutoConfigurationImportFilter 接口去过滤自动配置类是否符合其标注注解；（@Conditional是Spring4新提供的注解，它的作用是按照一定的条件进行判断，满足条件给容器注册bean。）&#13;
6. 然后触发 AutoConfigurationImportEvent 事件，告诉 ConditionEvaluationReport 条件评估报告器对象来分别记录符合条件和 exclude 的自动配置类；&#13;
7. 最后spring再将最后筛选后的自动配置类导入IOC容器中。</a>
</h3>
<h3 class="topic">
<a name="6ddlramp1afra6khdp7m4gnln3">&nbsp;&nbsp;@ComponentScan 注解扫描&#13;
&#13;
常用属性如下：&#13;
basePackages、value：指定扫描路径，如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径&#13;
basePackageClasses：指定具体扫描的类&#13;
includeFilters：指定满足Filter条件的类&#13;
excludeFilters：指定排除Filter条件的类</a>
</h3>
<h3 class="topic">
<a name="2fae8nirgivkn8mtkmnm84mebd">&nbsp;Run方法执行流程&#13;
SpringApplication(primarySources).run(args);</a>
</h3>
<h3 class="topic">
<a name="4v4trgk3r19vl5bg25v97qt893">&nbsp;&nbsp;第一步：SpringApplication初始化过程</a>
</h3>
<h3 class="topic">
<a name="57b78bmb8qvulj646c9unf0vh0">&nbsp;&nbsp;&nbsp;1. 推断应用类型，后面会根据类型初始化对应的环境（常用都是servlet环境）</a>
</h3>
<h3 class="topic">
<a name="3ife6m4s3ot4iig8g8la5fo6l6">&nbsp;&nbsp;&nbsp;2. classpath下 META-INF/spring.factories中已配置的 ApplicationContextInitializer初始化为实例对象</a>
</h3>
<h3 class="topic">
<a name="1h3p9ebot4o4l2eiv27vqccr2a">&nbsp;&nbsp;&nbsp;3. 初始化classpath下所有已配置的 ApplicationListener</a>
</h3>
<h3 class="topic">
<a name="060n8drncvf0f4911mh6o6lnj9">&nbsp;&nbsp;&nbsp;4. 根据调用栈，推断出 main 方法的类名</a>
</h3>
<h3 class="topic">
<a name="2ips0chdvd8hl058b2ljnada8k">&nbsp;&nbsp;第二步：执行run方法</a>
</h3>
<h3 class="topic">
<a name="1fmgt4s7k4l3h9voarlrod95ah">&nbsp;&nbsp;&nbsp;1. 获取并启动监听器</a>
</h3>
<h3 class="topic">
<a name="15n73qbd83ndgoff6dv7g9nnkh">&nbsp;&nbsp;&nbsp;&nbsp;SpringApplicationRunListeners负责在SpringBoot启动的不同阶段，广播出不同的消息， 传递给ApplicationListener监听器实现类。</a>
</h3>
<h3 class="topic">
<a name="1j4f50trgu8l1r9c9lu4ep8l0n">&nbsp;&nbsp;&nbsp;2. 构造应用上下文环境</a>
</h3>
<h3 class="topic">
<a name="2eiq5hl0c67c6uftqdioohh12f">&nbsp;&nbsp;&nbsp;&nbsp;应用上下文环境包括什么呢？&#13;
包括计算机的环境，Java环境，Spring的运行环境，Spring项目的配置（在SpringBoot中就是那个熟悉的application.properties/yml）等等。</a>
</h3>
<h3 class="topic">
<a name="4i0em15c46gddai1i1e9c3ikjh">&nbsp;&nbsp;&nbsp;&nbsp;1. 创建并配置相应的环境&#13;
2. 根据用户配置，配置 environment系统环境（多环境下）&#13;
3. 启动相应的监听器，其中一个重要的监听器 ConfigFileApplicationListener 就是加载项目 配置文件（,porperties/.yaml）的监听器。</a>
</h3>
<h3 class="topic">
<a name="2nrpsm11b6vecf3fb6e3bktft2">&nbsp;&nbsp;&nbsp;3. 初始化应用上下文&#13;
当前范围当前环境的属性集合</a>
</h3>
<h3 class="topic">
<a name="4jd4635bkldd9fje7mfvhlgu65">&nbsp;&nbsp;&nbsp;&nbsp;判断应用类型，并实例化AnnotationConfigServletWebServerApplicationContext&#13;
同时也触发了GenericApplicationContext类的构造函数，从而IoC容器也创建了</a>
</h3>
<h3 class="topic">
<a name="7sd9l0uvbt11unrt1slu0u8pk1">&nbsp;&nbsp;&nbsp;&nbsp;DefaultListableBeanFactory就是IoC容器</a>
</h3>
<h3 class="topic">
<a name="5k6m4nbm4b060ai2mgbj29f8of">&nbsp;&nbsp;&nbsp;&nbsp;实例化SpringBootExceptionReporter.class，用来支持报告关于启动的错误</a>
</h3>
<h3 class="topic">
<a name="2n9ca4bbbikv9oh00v10t2ftp0">&nbsp;&nbsp;&nbsp;4. 刷新应用上下文前的准备阶段&#13;
prepareContext()</a>
</h3>
<h3 class="topic">
<a name="2f6cien6vbbl7538299ck0s0c6">&nbsp;&nbsp;&nbsp;&nbsp;【了解】&#13;
1. 设置容器环境&#13;
2. 执行容器后置处理&#13;
3. 执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种 方式自定义的&#13;
4. 向各个监听器发送容器已经准备好的事件&#13;
5. 将main函数中的args参数封装成单例Bean，注册进容器</a>
</h3>
<h3 class="topic">
<a name="68phrgiodggdh7vuitdh9v2bgj">&nbsp;&nbsp;&nbsp;&nbsp;Load the Sources 【重点】&#13;
&#13;
1. 在getAllSources()中拿到了项目的启动类&#13;
&#13;
2. 进入load()方法，创建 BeanDefinitionLoader&#13;
[Spring在容器启动的时候，会将类解析成spring内部的beanDefintion结构，并将beanDefinition存储到DefaultListableBeanFactory的map中]&#13;
&#13;
3. createBeanDefinitionLoader()构造方法，定义&#13;
	this.annotatedReader //注解形式的Bean定义读取器&#13;
	this.xmlReader           //XML形式的Bean定义读取器&#13;
	this.scanner              //类路径扫描器&#13;
&#13;
4. 进入loader.load()方法，将 启动类的 BeanDefinition注册进 beanDefinitionMap</a>
</h3>
<h3 class="topic">
<a name="2i0lgg39erjrlocoppi9hosjq9">&nbsp;&nbsp;&nbsp;5. 刷新应用上下文&#13;
refreshContext()</a>
</h3>
<h3 class="topic">
<a name="584tmi0j9pgmstu0v4n7674pog">&nbsp;&nbsp;&nbsp;&nbsp;AbstractApplicationContext.refresh() 其实已经交给Spring来完成Bean创建</a>
</h3>
<h3 class="topic">
<a name="56r8sse9tl32qhq9erma4eql4k">&nbsp;&nbsp;&nbsp;&nbsp;【重点 自动配置的核心源码】&#13;
invokeBeanFactoryPostProcessors(beanFactory);</a>
</h3>
<h3 class="topic">
<a name="510689h3o2theji429le8c5ovd">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;【（IOC容器的初始化过程】</a>
</h3>
<h3 class="topic">
<a name="2d0bcb2en2rqvvupgnfj82orfi">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. BeanDefinition的Resource定位&#13;
常规的在SpringBoot中有三种实现定位&#13;
第一个是主类所在包的&#13;
第二个是SPI扩展机制(spring.factories)实现的自动装配（比如各种starter）&#13;
第三种就是@Import注解指定的类</a>
</h3>
<h3 class="topic">
<a name="54dqcv7onfsjs2pdism38jd9el">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. BeanDefinition的载入</a>
</h3>
<h3 class="topic">
<a name="0n4dnggcanhsva9ceu27q3qskh">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. 向IoC容器注册BeanDefinition&#13;
this.reader.loadBeanDefinitions(configClasses);</a>
</h3>
<h3 class="topic">
<a name="05gh430i530t628neucsp4p3ot">&nbsp;&nbsp;&nbsp;6. 刷新应用上下文后的扩展接口</a>
</h3>
<h3 class="topic">
<a name="0h1l4jt76e8gpta2b28o24bd07">&nbsp;&nbsp;&nbsp;&nbsp;扩展接口，设计模式中的模板方法，默认为空实现。&#13;
有自定义需求，可以重写该方法。比如打印一些启动结束log，或者一些其它后置处理</a>
</h3>
<h3 class="topic">
<a name="1n9o5qh3un36eorudoud53khhu">&nbsp;子主题 8</a>
</h3>
<h3 class="topic">
<a name="516483j2nbc1s4ll7goctv5i49">&nbsp;自定义Starter</a>
</h3>
<h3 class="topic">
<a name="54fmhe4uaus1d4vkidsnu5q7ju">&nbsp;&nbsp;Starter概述和机制</a>
</h3>
<h3 class="topic">
<a name="4l1cgo5qbdo9dipkvaincpamoq">&nbsp;&nbsp;&nbsp;在maven中引入starter依赖，SpringBoot就能自动扫描到要加载的信息并&#13;
启动相应的默认配置。所有这些依赖模块都遵循&ldquo;约定大于配置&rdquo;的理念。</a>
</h3>
<h3 class="topic">
<a name="70vqjlegqhpg0ugotv1bre28lp">&nbsp;&nbsp;&nbsp;使用场景：&#13;
1. 动态数据源。&#13;
2. 登录模块。&#13;
3. 基于AOP技术实现日志切面。</a>
</h3>
<h3 class="topic">
<a name="6hukfqrpjhlo9rbmit87vtl52h">&nbsp;&nbsp;&nbsp;自定义命名规则：&#13;
xxx-spring-boot-starter&#13;
官方命名规则：&#13;
spring-boot-starter-xxx</a>
</h3>
<h3 class="topic">
<a name="7h2oq3o04sgfossrcsi0gqqoq7">&nbsp;&nbsp;自定义Starter的实现</a>
</h3>
<h3 class="topic">
<a name="2ehpg3gm3b16l72l4kp53jv7jr">&nbsp;内嵌Tomcat原理</a>
</h3>
<h3 class="topic">
<a name="7bsscsqk17ugskp9vk8nog6h9u">&nbsp;&nbsp;SpringBoot 默认使用tomcat作为servlet容器&#13;
切换容器只需exclusion tomcat然后引入jetty</a>
</h3>
<h3 class="topic">
<a name="3nbleaac5qmh1oc1go3826l93s">&nbsp;&nbsp;1. 通过自动配置加载ServletWebServerFactoryAutoConfiguration&#13;
2. 注解上的ServerProperties用于配置参数 （server.port等）&#13;
3. 注解Import引入EmbeddedTomcat&#13;
4. 创建TomcatServletWebServerFactory工厂&#13;
5. 通过getWebServer()实例化一个tomcat</a>
</h3>
<h3 class="topic">
<a name="1gc03oi7ogbvugniq8ttalqll6">&nbsp;&nbsp;getWebServer()方法是在哪里调用的呢？&uarr;&#13;
&#13;
刷新上下文refreshContext() --&gt; refresh() --&gt; onRefresh() --&gt;&#13;
[ 会获取嵌入式的Servlet容器工厂，并通过工厂来获取Servlet容器 ]&#13;
ServletWebServerApplicationContext中的createWebServer() --&gt;&#13;
[ 先获取嵌入式Servlet容器工厂 ]&#13;
ServletWebServerFactory factory = getWebServerFactory();&#13;
this.webServer = factory.getWebServer(getSelfInitializer());&#13;
&#13;
刷新上下文refreshContext() --&gt; finishRefresh() --&gt; startWebServer()&#13;
[ 启动"在Tomcat启动时"就要完成启动的Servlet，检查Connector是否都启动完成，打印最终启动完成日志 ]</a>
</h3>
<h3 class="topic">
<a name="5momngeak82hfngh3fvbasp4ct">&nbsp;&nbsp;Tomcat 启动流程</a>
</h3>
<h3 class="topic">
<a name="7dgn7gtegjg43dc4qj1s9t7q46">&nbsp;自动配置SpringMVC</a>
</h3>
<h3 class="topic">
<a name="5tv5vei5kdm2up8or3m8fc8ujk">&nbsp;&nbsp;Servlet3.0规范中规定，要添加一个Servlet，除了采用xml配置的方式&#13;
还有一种通过代码的方式，伪代码如下：&#13;
servletContext.addServlet(name, this.servlet);</a>
</h3>
<h3 class="topic">
<a name="4im7qqs84adsr7hgcmh2qnht5j">&nbsp;&nbsp;1. DispatcherServletAutoConfiguration自动配置类；&#13;
2. 配置DispatcherServletConfiguration，生成一个DispatcherServlet的Bean对象；&#13;
3. 配置DispatcherServletRegistrationConfiguration 注册类，&#13;
    负责将dispatcherServlet给注册到ServletContext中  &darr;</a>
</h3>
<h3 class="topic">
<a name="3s6p7hdej8ag2svf3crej5l5qr">&nbsp;&nbsp;注册DispatcherServlet到ServletContext &#13;
&#13;
getSelfInitializer() --&gt; beans.onStartup(servletContext)</a>
</h3>
<h3 class="topic">
<a name="1hs803030dl3pgbio7qu6vfi1e">&nbsp;&nbsp;&nbsp;DispatchServletRegistrationBean类图</a>
</h3>
<h2 class="topic">
<a name="2drel9j6mfbmc7p13po05q1u1l">SpringBoot数据访问</a>
</h2>
<h3 class="topic">
<a name="57rcs9k2eloehtu3n5htoh6gh2">&nbsp;数据源自动配置</a>
</h3>
<h3 class="topic">
<a name="5asoicg3ha3cols35t8p7lp6hm">&nbsp;&nbsp;连接池配置&#13;
SpringBoot提供了三种数据库连接池：&#13;
1. HikariCP （默认）&#13;
2. Commons DBCP2&#13;
3. Tomcat JDBC Connection Pool</a>
</h3>
<h3 class="topic">
<a name="0fgri9ghr21bsqmojbaj9ijfes">&nbsp;&nbsp;源码剖析&#13;
配置类：DataSourceAutoConfiguration&#13;
参数配置：DataSourceProperties&#13;
内部类： PooledDataSourceConfiguration&#13;
@Import： 按条件生效 Hikari 、tomcat、DBCP2、Generic 等&#13;
&#13;
使用DataSourceBuilder 建造数据源，利用反射创建type数据源，然后绑定相关属性</a>
</h3>
<h3 class="topic">
<a name="0jqb6pbag569e93t6ia9g8ctfm">&nbsp;Druid连接池的配置</a>
</h3>
<h3 class="topic">
<a name="0vbciojli7ih2cc81u8u9r9k43">&nbsp;&nbsp;第三方的连接池，编写一个类与其属性进行绑定</a>
</h3>
<h3 class="topic">
<a name="1tno072kbh17e0ai12pg73nbkd">&nbsp;SpringBoot整合Mybatis</a>
</h3>
<h3 class="topic">
<a name="309359liq33rgvfshgteekvlb2">&nbsp;&nbsp;MyBatis团队自行适配了对应的启动器 [ 从命名可以看出来 ]&#13;
&lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;</a>
</h3>
<h3 class="topic">
<a name="2o8bk61pmu6u7ak38tpd8mkfcp">&nbsp;Mybatis自动配置剖析</a>
</h3>
<h3 class="topic">
<a name="4h8n3uggbbq9cquoedpg7hn1gs">&nbsp;&nbsp;配置类：MybatisAutoConfiguration.java&#13;
1. 注解中有个MybatisProperties类，该类对应的是mybatis的配置文件&#13;
2. sqlSessionFactory方法，作用是创建SqlSessionFactory类、Configuration类&#13;
3. sqlSessionTemplate，作用是与mapperProxy代理类有关</a>
</h3>
<h3 class="topic">
<a name="6r6d8q6uchic4dpokilbddpaap">&nbsp;&nbsp;mapper代理对象&#13;
1. 包扫描注解@MapperScan(basePackages = "com.mybatis.mapper")&#13;
2. @Import 导入MapperScannerRegistrar类&#13;
3. 根据注解value值开始扫描scaner.doscan()&#13;
4. 设置每个mapper接口的beanClass属性为MapperFactoryBean类型并加入&#13;
到spring的bean容器中&#13;
5. spring开始执行实例化时返回的对象为getObject()中返回的对象&#13;
6. getObject()通过动态代理生成的mapper接口实现类</a>
</h3>
<h3 class="topic">
<a name="2hvhhtt3rvgvv3nmk9qli2bmlb">&nbsp;动态数据源</a>
</h3>
<h3 class="topic">
<a name="3l25e6th0dndmarif17t56k3dg">&nbsp;&nbsp;实现分析：把多个数据源以map(k,v)的形式储存，Dao层执行sql时传入key值确定源&#13;
关键在于AbstractRoutingDataSource [springframework提供的抽象类]&#13;
方法：getConnection() --&gt; determineTargetDataSource() --&gt; lookupkey</a>
</h3>
<h3 class="topic">
<a name="1rqlhsfoijj6t474iqs16pcl56">&nbsp;&nbsp;动态数据源思路分析</a>
</h3>
<h2 class="topic">
<a name="28no2oe3hgij45b0g87vl0uht6">SpringBoot缓存深入</a>
</h2>
<h3 class="topic">
<a name="1rb9ojgpvch0p4jbuh2gp3c2q3">&nbsp;JSR107</a>
</h3>
<h3 class="topic">
<a name="0k0s5nq0hloqssvf51a8aph0rg">&nbsp;&nbsp;Java Specification Requests，提交java规范&#13;
JSR-107是关于如何使用缓存的规范</a>
</h3>
<h3 class="topic">
<a name="77g0d34v8rdhbueihvmc6tqhcu">&nbsp;&nbsp;Java Caching 定义了5个核心接口&#13;
1. CachingProvider（缓存提供者）&#13;
2. CacheManager（缓存管理器）&#13;
3. Cache （缓存）&#13;
4. Entry（缓存键值对）&#13;
5. Expiry（缓存时效）</a>
</h3>
<h3 class="topic">
<a name="04ul01rhapprej6r8qvqto7qr4">&nbsp;缓存概念&amp;缓存注解</a>
</h3>
<h3 class="topic">
<a name="0ajrlcd96pn9o54gkp5h7ak25o">&nbsp;&nbsp;缓存抽象：Spring Cache 只负责维护抽象层&#13;
接口Cache/CacheManager + 实现Redis/Ehcache&#13;
使用Spring缓存抽象时我们需要关注以下两点：&#13;
1. 确定那些方法需要被缓存&#13;
2. 缓存策略 （key,value策略）</a>
</h3>
<h3 class="topic">
<a name="51n6s58c1mf5a9dp8urqh42u1n">&nbsp;&nbsp;缓存注解：&#13;
1. @Cacheable 缓存查询&#13;
2. @CacheEvict 缓存清空&#13;
3. @CachePut 缓存更新&#13;
4. @EnableCaching 开启缓存&#13;
【非注解】&#13;
5. keyGenerator key生产策略&#13;
6. serialize value序列化策略</a>
</h3>
<h3 class="topic">
<a name="452jjv17cavnr4m1mqpftpr9gq">&nbsp;Spring缓存使用</a>
</h3>
<h3 class="topic">
<a name="7c4so2f05n5ffsjg9vmfcg3p8u">&nbsp;&nbsp;@Cacheable : 缓存查询：会将该方法的返回值存到缓存中&#13;
1. value/cacheNames：指定缓存的名称&#13;
2. key：缓存数据时指定key值(key,value)，默认是方法的参数值，也可以使用spEL来计算key的值&#13;
3. keyGenerator：key的生成策略，和key进行二选一 ，自定义keyGenerator&#13;
4. cacheManager：指定缓存管理器  redis:emp   ehcache:emp&#13;
5. cacheResolver: 功能跟cacheManager相同，二选一即可&#13;
6. condition：条件属性，满足这个条件才会进行缓存&#13;
7. unless: 否定条件：满足这个条件，不进行缓存&#13;
8. sync: 是否使用异步模式进行缓存 true&#13;
  (1) condition/unless 同时满足，不缓存&#13;
  (2) sync的值为true的时候，unless不被支持</a>
</h3>
<h3 class="topic">
<a name="10rnj024r1v3mnlfu15te2ejaa">&nbsp;缓存自动配置源码剖析</a>
</h3>
<h3 class="topic">
<a name="26uchqr564ktdnpv8rgpebrrbm">&nbsp;&nbsp;一、缓存的自动配置：&#13;
配置类CacheAutoConfiguration&#13;
缓存参数类CacheProperties&#13;
@Import CacheConfigurationImportSelector&#13;
重写selectImport() 导入针对缓存的组件类&#13;
Spring默认生效SimpleCacheConfiguration&#13;
创建ConcurrentMapCacheManager存入IOC容器 </a>
</h3>
<h3 class="topic">
<a name="29mfv0536nihvn7p82u2t14m6j">&nbsp;&nbsp;缓存的底层数据结构：ConcurrentMapCache&#13;
value的底层数据结构：ConCurrentHashMap</a>
</h3>
<h3 class="topic">
<a name="1766clkvd5cd84ot8u390rljho">&nbsp;&nbsp;缓存使用时代码剖析：&#13;
ConcurrentMapCache.getCache()&#13;
第一次查询从缓存中拿不到值，创建缓存&#13;
ConcurrentMapCache.lookup()找不到&#13;
查询数据库后，调用put往store存入ConCurrentHashMap&#13;
第二次查询从缓存中拿到值&#13;
ConcurrentMapCache.lookup()根据key找到value&#13;
不会继续访问数据类</a>
</h3>
<h3 class="topic">
<a name="3d697b579j7cgj0igr0u3atb1j">&nbsp;缓存注解的使用</a>
</h3>
<h3 class="topic">
<a name="42bb7hoo2qkphchsg6o3kdnck7">&nbsp;&nbsp;@CachePut 用于更新缓存&#13;
更新缓存时一定要和想更新的缓存有相同的缓存名称和相同的key</a>
</h3>
<h3 class="topic">
<a name="0uq4b3tb406uqprpl06q9nj78h">&nbsp;&nbsp;@CacheEvict 用于清空缓存&#13;
属性：&#13;
allEntries：是否清除指定缓存中的所有键值对，默认为false&#13;
beforeInvocation：在@CacheEvict注解的方法调用之前清除指定缓存，默认为false&#13;
考虑出现异常。</a>
</h3>
<h3 class="topic">
<a name="6mmqn7520hb0dqkn2q05qta65k">&nbsp;&nbsp;@CacheConfig&#13;
作用：标注在类上，抽取缓存相关注解的公共配置，可抽取的公共配置有缓存名字、主键生成器、缓存管理器等</a>
</h3>
<h3 class="topic">
<a name="16lvi9ppcni4979vprvjhsros3">&nbsp;基于Redis的缓存实现</a>
</h3>
<h3 class="topic">
<a name="7vb0rrtlqtvb60om64anqb0337">&nbsp;&nbsp;配置类RedisAutoConfiguration&#13;
参数类RedisProperties&#13;
创建RedisTemplate、StringRdisTemplate&#13;
缓存类需要序列化&#13;
可以切换为使用JSON格式进行对象的序列化操作</a>
</h3>
<h3 class="topic">
<a name="5dagfn66cej1v86smrlp75qigc">&nbsp;&nbsp;Redis注解默认序列化机制&#13;
JdkSerializationRedisSerializer</a>
</h3>
<h3 class="topic">
<a name="51qnk5tbcecs8rn9t40300o254">&nbsp;&nbsp;自定义RedisCacheManager</a>
</h3>
<h2 class="topic">
<a name="4n9bnspl6vj238clguodai4omt">SpringBoot部署和监控</a>
</h2>
<h3 class="topic">
<a name="6lpfmpaehvte80lslvd6gs4lnk">&nbsp;子主题 1</a>
</h3>
<h3 class="topic">
<a name="2qhu8eb55r9897nekujvtaes1c">&nbsp;子主题 2</a>
</h3>
</body>
</html>
